From 63c30e3123bcc4a1dc52cb5c7dece0efe4faf62a Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Fri, 3 Mar 2006 15:05:25 +0100 Subject: [PATCH] Domain0 identifies IOAPIC by physical base address rather than BIOS-assigned identifier. This seems a more reliable method since it seems that we always trust the base address and we don't need to work around renumbering/rebasing as we do with APICIDs. This is an alternative to the Yonah networking patch from Allen Kay at Intel. Signed-off-by: Keir Fraser --- .../arch/i386/kernel/io_apic-xen.c | 8 +-- .../arch/x86_64/kernel/io_apic-xen.c | 8 +-- xen/arch/x86/io_apic.c | 65 +++++++------------ xen/arch/x86/physdev.c | 16 +++-- xen/include/public/physdev.h | 4 +- 5 files changed, 46 insertions(+), 55 deletions(-) diff --git a/linux-2.6-xen-sparse/arch/i386/kernel/io_apic-xen.c b/linux-2.6-xen-sparse/arch/i386/kernel/io_apic-xen.c index 003300858a..53704a58d7 100644 --- a/linux-2.6-xen-sparse/arch/i386/kernel/io_apic-xen.c +++ b/linux-2.6-xen-sparse/arch/i386/kernel/io_apic-xen.c @@ -61,8 +61,8 @@ static inline unsigned int xen_io_apic_read(unsigned int apic, unsigned int reg) int ret; op.cmd = PHYSDEVOP_APIC_READ; - op.u.apic_op.apic = mp_ioapics[apic].mpc_apicid; - op.u.apic_op.offset = reg; + op.u.apic_op.apic_physbase = mp_ioapics[apic].mpc_apicaddr; + op.u.apic_op.reg = reg; ret = HYPERVISOR_physdev_op(&op); if (ret) return ret; @@ -74,8 +74,8 @@ static inline void xen_io_apic_write(unsigned int apic, unsigned int reg, unsign physdev_op_t op; op.cmd = PHYSDEVOP_APIC_WRITE; - op.u.apic_op.apic = mp_ioapics[apic].mpc_apicid; - op.u.apic_op.offset = reg; + op.u.apic_op.apic_physbase = mp_ioapics[apic].mpc_apicaddr; + op.u.apic_op.reg = reg; op.u.apic_op.value = value; HYPERVISOR_physdev_op(&op); } diff --git a/linux-2.6-xen-sparse/arch/x86_64/kernel/io_apic-xen.c b/linux-2.6-xen-sparse/arch/x86_64/kernel/io_apic-xen.c index 5d51a7f3b7..fd72947df7 100644 --- a/linux-2.6-xen-sparse/arch/x86_64/kernel/io_apic-xen.c +++ b/linux-2.6-xen-sparse/arch/x86_64/kernel/io_apic-xen.c @@ -108,8 +108,8 @@ static inline unsigned int xen_io_apic_read(unsigned int apic, unsigned int reg) int ret; op.cmd = PHYSDEVOP_APIC_READ; - op.u.apic_op.apic = mp_ioapics[apic].mpc_apicid; - op.u.apic_op.offset = reg; + op.u.apic_op.apic_physbase = mp_ioapics[apic].mpc_apicaddr; + op.u.apic_op.reg = reg; ret = HYPERVISOR_physdev_op(&op); if (ret) return ret; @@ -121,8 +121,8 @@ static inline void xen_io_apic_write(unsigned int apic, unsigned int reg, unsign physdev_op_t op; op.cmd = PHYSDEVOP_APIC_WRITE; - op.u.apic_op.apic = mp_ioapics[apic].mpc_apicid; - op.u.apic_op.offset = reg; + op.u.apic_op.apic_physbase = mp_ioapics[apic].mpc_apicaddr; + op.u.apic_op.reg = reg; op.u.apic_op.value = value; HYPERVISOR_physdev_op(&op); } diff --git a/xen/arch/x86/io_apic.c b/xen/arch/x86/io_apic.c index aef5d64b5a..e71603c125 100644 --- a/xen/arch/x86/io_apic.c +++ b/xen/arch/x86/io_apic.c @@ -1634,16 +1634,6 @@ static inline void check_timer(void) "report. Then try booting with the 'noapic' option"); } -#define NR_IOAPIC_BIOSIDS 256 -static u8 ioapic_biosid_to_apic_enum[NR_IOAPIC_BIOSIDS]; -static void store_ioapic_biosid_mapping(void) -{ - u8 apic; - memset(ioapic_biosid_to_apic_enum, ~0, NR_IOAPIC_BIOSIDS); - for ( apic = 0; apic < nr_ioapics; apic++ ) - ioapic_biosid_to_apic_enum[mp_ioapics[apic].mpc_apicid] = apic; -} - /* * * IRQ's that are handled by the PIC in the MPS IOAPIC case. @@ -1655,8 +1645,6 @@ static void store_ioapic_biosid_mapping(void) void __init setup_IO_APIC(void) { - store_ioapic_biosid_mapping(); - enable_IO_APIC(); if (acpi_ioapic) @@ -1840,50 +1828,45 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int a #endif /*CONFIG_ACPI_BOOT*/ +static int ioapic_physbase_to_id(unsigned long physbase) +{ + int apic; + for ( apic = 0; apic < nr_ioapics; apic++ ) + if ( mp_ioapics[apic].mpc_apicaddr == physbase ) + return apic; + return -EINVAL; +} -int ioapic_guest_read(int apicid, int address, u32 *pval) +int ioapic_guest_read(unsigned long physbase, unsigned int reg, u32 *pval) { - u32 val; - int apicenum; - union IO_APIC_reg_00 reg_00; + int apic; unsigned long flags; - if ( (apicid >= NR_IOAPIC_BIOSIDS) || - ((apicenum = ioapic_biosid_to_apic_enum[apicid]) >= nr_ioapics) ) - return -EINVAL; + if ( (apic = ioapic_physbase_to_id(physbase)) < 0 ) + return apic; spin_lock_irqsave(&ioapic_lock, flags); - val = io_apic_read(apicenum, address); + *pval = io_apic_read(apic, reg); spin_unlock_irqrestore(&ioapic_lock, flags); - /* Rewrite APIC ID to what the BIOS originally specified. */ - if ( address == 0 ) - { - reg_00.raw = val; - reg_00.bits.ID = apicid; - val = reg_00.raw; - } - - *pval = val; return 0; } -int ioapic_guest_write(int apicid, int address, u32 val) +int ioapic_guest_write(unsigned long physbase, unsigned int reg, u32 val) { - int apicenum, pin, irq; + int apic, pin, irq; struct IO_APIC_route_entry rte = { 0 }; struct irq_pin_list *entry; unsigned long flags; - if ( (apicid >= NR_IOAPIC_BIOSIDS) || - ((apicenum = ioapic_biosid_to_apic_enum[apicid]) >= nr_ioapics) ) - return -EINVAL; + if ( (apic = ioapic_physbase_to_id(physbase)) < 0 ) + return apic; /* Only write to the first half of a route entry. */ - if ( (address < 0x10) || (address & 1) ) + if ( (reg < 0x10) || (reg & 1) ) return 0; - pin = (address - 0x10) >> 1; + pin = (reg - 0x10) >> 1; *(u32 *)&rte = val; rte.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS); @@ -1899,7 +1882,7 @@ int ioapic_guest_write(int apicid, int address, u32 val) if ( rte.delivery_mode > dest_LowestPrio ) { printk("ERROR: Attempt to write weird IOAPIC destination mode!\n"); - printk(" APIC=%d/%d, lo-reg=%x\n", apicid, pin, val); + printk(" APIC=%d/%d, lo-reg=%x\n", apic, pin, val); return -EINVAL; } @@ -1924,19 +1907,19 @@ int ioapic_guest_write(int apicid, int address, u32 val) /* Record the pin<->irq mapping. */ for ( entry = &irq_2_pin[irq]; ; entry = &irq_2_pin[entry->next] ) { - if ( (entry->apic == apicenum) && (entry->pin == pin) ) + if ( (entry->apic == apic) && (entry->pin == pin) ) break; if ( !entry->next ) { - add_pin_to_irq(irq, apicenum, pin); + add_pin_to_irq(irq, apic, pin); break; } } } spin_lock_irqsave(&ioapic_lock, flags); - io_apic_write(apicenum, 0x10 + 2 * pin, *(((int *)&rte) + 0)); - io_apic_write(apicenum, 0x11 + 2 * pin, *(((int *)&rte) + 1)); + io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&rte) + 0)); + io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&rte) + 1)); spin_unlock_irqrestore(&ioapic_lock, flags); return 0; diff --git a/xen/arch/x86/physdev.c b/xen/arch/x86/physdev.c index 418392da92..c3baee8572 100644 --- a/xen/arch/x86/physdev.c +++ b/xen/arch/x86/physdev.c @@ -11,8 +11,12 @@ #include #include -extern int ioapic_guest_read(int apicid, int address, u32 *pval); -extern int ioapic_guest_write(int apicid, int address, u32 pval); +extern int +ioapic_guest_read( + unsigned long physbase, unsigned int reg, u32 *pval); +extern int +ioapic_guest_write( + unsigned long physbase, unsigned int reg, u32 pval); /* * Demuxing hypercall. @@ -49,7 +53,9 @@ long do_physdev_op(struct physdev_op *uop) if ( !IS_PRIV(current->domain) ) break; ret = ioapic_guest_read( - op.u.apic_op.apic, op.u.apic_op.offset, &op.u.apic_op.value); + op.u.apic_op.apic_physbase, + op.u.apic_op.reg, + &op.u.apic_op.value); break; case PHYSDEVOP_APIC_WRITE: @@ -57,7 +63,9 @@ long do_physdev_op(struct physdev_op *uop) if ( !IS_PRIV(current->domain) ) break; ret = ioapic_guest_write( - op.u.apic_op.apic, op.u.apic_op.offset, op.u.apic_op.value); + op.u.apic_op.apic_physbase, + op.u.apic_op.reg, + op.u.apic_op.value); break; case PHYSDEVOP_ASSIGN_VECTOR: diff --git a/xen/include/public/physdev.h b/xen/include/public/physdev.h index 9124ca5474..b9486d5fa9 100644 --- a/xen/include/public/physdev.h +++ b/xen/include/public/physdev.h @@ -33,8 +33,8 @@ typedef struct physdevop_set_iobitmap { typedef struct physdevop_apic { /* IN */ - uint32_t apic; - uint32_t offset; + unsigned long apic_physbase; + uint32_t reg; /* IN or OUT */ uint32_t value; } physdevop_apic_t; -- 2.30.2